package org.mobai.flow.utils;

import cn.hutool.core.util.ObjectUtil;
import org.camunda.bpm.engine.form.FormField;
import org.camunda.bpm.model.bpmn.BpmnModelInstance;
import org.camunda.bpm.model.bpmn.instance.BaseElement;
import org.camunda.bpm.model.bpmn.instance.camunda.CamundaFormField;
import org.camunda.bpm.model.bpmn.instance.camunda.CamundaProperties;
import org.camunda.bpm.model.bpmn.instance.camunda.CamundaProperty;
import org.camunda.bpm.model.xml.ModelInstance;
import org.camunda.bpm.model.xml.instance.ModelElementInstance;
import org.mobai.flow.constant.CamundaConstant;
import org.mobai.flow.enums.BpmnBaseVarEnum;
import org.mobai.flow.pojo.bpmn.FormProperty;

import java.util.*;

/**
 * @author mobai
 */
public class FlowUtil {

    /**
     * 设置Camunda表单字段属性
     * 此方法将给定的表单属性（如隐藏、只读和必填）设置到Camunda表单字段中
     * 这在自动生成Camunda流程定义时非常有用，可以根据表单属性来设定字段的行为
     *
     * @param formProperty     表单属性对象，包含字段的隐藏、只读和必填状态
     * @param camundaFormField Camunda表单字段对象，用于设置属性
     */
    public static void setCamundaProperties(FormProperty formProperty, CamundaFormField camundaFormField) {
        // 获取表单字段的模型实例
        ModelInstance modelInstance = camundaFormField.getModelInstance();

        // 创建新的Camunda属性集合实例
        CamundaProperties camundaProperties = modelInstance.newInstance(CamundaProperties.class);

        // 创建用于表示隐藏属性的Camunda属性实例
        CamundaProperty hidden = modelInstance.newInstance(CamundaProperty.class);
        // 设置隐藏属性的ID和值
        hidden.setCamundaId(CamundaConstant.FIELD_HIDDEN);
        hidden.setCamundaValue(String.valueOf(formProperty.getHidden()));

        // 创建用于表示只读属性的Camunda属性实例
        CamundaProperty readonly = modelInstance.newInstance(CamundaProperty.class);
        // 设置只读属性的ID和值
        readonly.setCamundaId(CamundaConstant.FIELD_READONLY);
        readonly.setCamundaValue(String.valueOf(formProperty.getReadonly()));

        // 创建用于表示必填属性的Camunda属性实例
        CamundaProperty required = modelInstance.newInstance(CamundaProperty.class);
        // 设置必填属性的ID和值
        required.setCamundaId(CamundaConstant.FIELD_REQUIRED);
        required.setCamundaValue(String.valueOf(formProperty.getRequired()));

        // 将隐藏、只读和必填属性添加到Camunda属性集合中
        camundaProperties.addChildElement(hidden);
        camundaProperties.addChildElement(readonly);
        camundaProperties.addChildElement(required);

        // 将包含所有属性的Camunda属性集合设置到表单字段中
        camundaFormField.setCamundaProperties(camundaProperties);
    }


    /**
     * 校验表单字段
     * 此方法主要用于在表单提交前校验填写的数据是否符合要求，包括是否为必填项以及处理只读项
     *
     * @param params     表单提交的参数，键为字段ID，值为字段值
     * @param formFields 表单字段配置，包含字段ID，标签，是否必填，是否只读等信息
     */
    public static void validateFormField(Map<String, Object> params, List<FormField> formFields) {
        List<String> baseFields = Arrays.stream(BpmnBaseVarEnum.values()).map(BpmnBaseVarEnum::getType).toList();
        baseFields.forEach(params::remove);
        // 遍历所有表单字段
        for (FormField formField : formFields) {
            // 如果当前字段为只读字段，则从提交参数中移除该字段值，避免后续处理
            if (Boolean.parseBoolean(formField.getProperties().get(CamundaConstant.FIELD_READONLY))) {
                params.remove(formField.getId());
                continue;
            }
            // 获取当前字段的值
            Object value = params.get(formField.getId());
            // 如果当前字段为必填字段
            if (Boolean.parseBoolean(formField.getProperties().get(CamundaConstant.FIELD_REQUIRED))) {
                // 如果值为空，则抛出运行时异常，提示必填字段未填写
                if (ObjectUtil.isEmpty(value)) {
                    throw new RuntimeException(formField.getLabel() + "参数为空");
                }
            }
        }
    }

    /**
     * 获取流程活动属性
     */
    public static Map<String, Object> getActivityProperty(BpmnModelInstance bpmnModelInstance, String taskDefinitionKey) {
        ModelElementInstance modelElementById = bpmnModelInstance.getModelElementById(taskDefinitionKey);
        Collection<CamundaProperty> camundaProperties = ((BaseElement) modelElementById).getExtensionElements().getElementsQuery().filterByType(CamundaProperties.class).singleResult().getCamundaProperties();
        HashMap<String, Object> properties = new HashMap<>();
        for (CamundaProperty camundaProperty : camundaProperties) {
            properties.put(camundaProperty.getCamundaName(), camundaProperty.getCamundaValue());
        }
        return properties;
    }


}
